#include <cassert>
#include <iostream>
#include <SceneGraph/scene_graph.h>
#include <SceneGraph/renderable.h>
#include <SceneGraph/animable.h>
#include <SceneGraph/customable.h>
using namespace std;

namespace PhysLeo {

void SceneGraph::readFromFile(const std::string& filename)
{
	//not implemented
	assert(0);
}

void SceneGraph::initGlResourceGraph() const
{
	initGlResourceNode(root_);
}

void SceneGraph::drawGraph(CameraInterface &camera) const
{
	drawNode(camera, root_);
}

void SceneGraph::initSimulationResourceGraph() const
{
	initSimulationResourceNode(root_);
}

void SceneGraph::runGraph(const float dt) const
{
	runNode(dt, root_);
}

void SceneGraph::transformDrawDataGraph() const
{
	transformDrawDataNode(root_);
}

void SceneGraph::updateDrawDataGraph() const
{
	updateDrawDataNode(root_);
}

void SceneGraph::initGlResourceNode(const std::shared_ptr<Node>& node)
{
    auto ptr = dynamic_cast<Renderable*>(node.get());
    if (ptr != nullptr)ptr->initGlResource();

    for (auto i = 0; i < node->size(); ++i)
    {
        initGlResourceNode(node->getChild(i));
    }
}

void SceneGraph::drawNode(CameraInterface & camera, const std::shared_ptr<Node>& node)
{
    for (auto i = 0; i < node->size(); ++i)
    {
        drawNode(camera, node->getChild(i));
    }

    auto ptr = dynamic_cast<Renderable*>(node.get());
    if (ptr != nullptr)ptr->draw(camera);
}

void SceneGraph::initSimulationResourceNode(const std::shared_ptr<Node>& node)
{
    for (auto i = 0; i < node->size(); ++i)
    {
        initSimulationResourceNode(node->getChild(i));
    }

    auto ptr = dynamic_cast<Animable*>(node.get());
    if (ptr != nullptr)ptr->initSimulationResource();

    auto ptr2 = dynamic_cast<Customable*>(node.get());
    if (ptr2 != nullptr)ptr2->initCustomResource();
}

void SceneGraph::runNode(float dt, const std::shared_ptr<Node>& node)
{
    for (auto i = 0; i < node->size(); ++i)
    {
        runNode(dt, node->getChild(i));
    }

    auto custom = dynamic_cast<Customable*>(node.get());
    if (custom != nullptr)custom->customOperation();

    auto ptr = dynamic_cast<Animable*>(node.get());
    if (ptr != nullptr)ptr->run(dt);
}

void SceneGraph::transformDrawDataNode(const std::shared_ptr<Node>& node)
{
    auto ptr = dynamic_cast<Animable*>(node.get());
    if (ptr != nullptr)ptr->transformDrawData();

    for (auto i = 0; i < node->size(); ++i)
    {
        transformDrawDataNode(node->getChild(i));
    }
}

void SceneGraph::updateDrawDataNode(const std::shared_ptr<Node>& node)
{
    auto ptr = dynamic_cast<Animable*>(node.get());
    if (ptr != nullptr)ptr->updateDrawData();

    for (auto i = 0; i < node->size(); ++i)
    {
        updateDrawDataNode(node->getChild(i));
    }
}

}